package controllers;

import models.Component;
import models.Day;
import models.DayTask;
import models.Event;
import models.Project;
import models.Task;
import models.User;
import models.UserStory;

import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.LinkedList;
import java.util.List;

import play.mvc.Controller;
import play.mvc.With;

/**
 * @author mohamedhisham,salma_hamed
 * 
 */
@With(Secure.class)
public class SprintBacklog extends Controller {
	/**
	 * 
	 * @param initialDate
	 *            the date before adding anything
	 * @param day
	 *            the day number which the initial date will be incremented with
	 * @return the new date after adding the number of days on it
	 */
	public static boolean assignedmem(long taskId) {
		long userId = Long.parseLong(session.get("userId"));
		Task task = Task.findById(taskId);
		User assignee = task.getTaskAssignee();
		User inSession = User.findById(userId);
		boolean x = false;
		if (assignee != null) {
			long assigneId = (Long) assignee.getEntityId();
			if (assigneId == userId)
				x = true;
		}

		return x;
	}

	/**
	 * this method gets a list of all the efforts for every task and if the
	 * there isn't any effort entered it's added as -1.0
	 * 
	 * @param eventId
	 *            the event id
	 * @param taskId
	 *            the task id
	 * @return
	 */
	public static List<DayTask> getEffortsTillNow2(long eventId, Long taskId) {
		Task t = Task.findById(taskId);
		Event event = Event.findById(eventId);

		Calendar st = new GregorianCalendar();

		st.set(event.startDate.get(Calendar.YEAR), event.startDate
				.get(Calendar.MONTH), event.startDate
				.get(Calendar.DAY_OF_WEEK_IN_MONTH));

		LinkedList<Double> effort = new LinkedList<Double>();
		double result = t.initialEffortEstimation;
		List<DayTask> remaineffort = new LinkedList<DayTask>();
		Calendar c1 = new GregorianCalendar();
		long duration;
		if (event.endDate.before(Calendar.getInstance()))
			duration = BurnDownChart.sprintDuration(event.startDate,
					event.endDate);
		else
			duration = BurnDownChart.sprintDuration(event.startDate, Calendar
					.getInstance());
		Day start = new Day(event.startDate);
		DayTask hp = new DayTask(result, t, start);
		int daysEntered = t.dayTasks.size();
		double tillnow = 0;
		while (duration != 0) {
			for (int j = 0; j < t.dayTasks.size(); j++) {
				c1 = t.dayTasks.get(j).day.date;
				if (dateCheck(c1, st)) {
					tillnow = tillnow + t.dayTasks.get(j).actualEffort;
					result = result - t.dayTasks.get(j).actualEffort;
					if (result < 0 || t.dayTasks.get(j).actualEffort < 0) {
						result = t.dayTasks.get(j).actualEffort - tillnow;
						if (result < 0) {
							result = 0;
						}
						t.dayTasks.get(j).actualEffort = result;
					}
					hp = t.dayTasks.get(j);
					break;
				}
			}
			if (daysEntered != 0) {
				effort.addLast(result);
				hp.actualEffort = result;
				remaineffort.add(hp);
				st.add(Calendar.DAY_OF_YEAR, 1);
				duration--;
				daysEntered--;
			} else {
				for (int i = 0; i < duration; i++) {
					remaineffort.add(new DayTask(-1.0, hp.task, hp.day));
					effort.addLast(-1.0);
				}
				break;
			}
		}
		return remaineffort;
	}

	/**
	 * @param projectID
	 *            takes the project id as input to make the sprint backlog of
	 *            this project
	 * @param eventID
	 *            takes the sprint id as input to make the sprint backlog of
	 *            this sprint return the all tasks and all stories of that
	 *            sprint, list of the sprint days to view the sprint duration
	 *            cells in the backlog
	 */
	public static void viewSprintBacklog(final Long projectID,
			final Long eventID) {

		Security.checkAccess("View the sprint backlog", projectID,
				Project.class.getName());
		Event sp = Event.find("byId", eventID).first();
		Project pro = Project.find("byId", projectID).first();
		for (int k = 0; k < pro.events.size(); k++) {
			if (pro.events.get(k).getEntityId() == sp.getEntityId()) {
				List<Task> allPTasks = new LinkedList<Task>();
				List<UserStory> allPs = new LinkedList<UserStory>();
				List<Integer> forSprintduration = new LinkedList<Integer>();
				if (sp.type.type.equals("Sprint")) {
					long sd = BurnDownChart.sprintDuration(sp.startDate,
							sp.endDate);
					for (int j = 1; j < sd + 1; j++) {
						forSprintduration.add(j);
					}
					allPs = Events.getEventUserStories(sp);
					allPTasks = Events.getEventTasksNotHaveUserStory(sp);
					render(allPTasks, forSprintduration, allPs, sp, sd, pro);
				}
			}
		}
	}

	/**
	 * @param component
	 *            takes the component id as input to the sprint backlog for a
	 *            specific component in the project
	 * @param projectID
	 *            takes the project id as input to make the sprint backlog of
	 *            this project
	 * @param sprintID
	 *            takes the sprint id as input to make the sprint backlog of
	 *            this sprint
	 * 
	 *            takes the list of tasks and user story in the sprint and then
	 *            checks on each user story if it belongs to the components user
	 *            story and puts them in a new list and sends it to the view
	 * 
	 */
	public static void viewComponentS(final long compID, final long projectID,
			final long eventID) {
		Security.checkAccess("View the sprint backlog", projectID,
				Project.class.getName());
		Component comp = Component.findById(compID);
		Event sp = Event.find("byId", eventID).first();
		Project pro = Project.find("byId", projectID).first();
		for (int k = 0; k < pro.events.size(); k++) {
			if (pro.events.get(k).getEntityId() == sp.getEntityId()) {
				List<Task> allPTasks = new LinkedList<Task>();
				List<UserStory> allPs = new LinkedList<UserStory>();
				List<Integer> forSprintduration = new LinkedList<Integer>();
				if (sp.type.type.equals("Sprint")) {
					long sd = BurnDownChart.sprintDuration(sp.startDate,
							sp.endDate);
					for (int j = 1; j < sd + 1; j++) {
						forSprintduration.add(j);
					}
					allPs = sp.getAssociatedwithEvent("S");
					allPTasks = sp.getAssociatedwithEvent("T");
					render(allPTasks, forSprintduration, allPs, sp, sd,
							projectID, compID, comp);
				}
			}
		}

	}

	/**
	 * This method takes 2 calendar day and compare if their equal.
	 * 
	 * @param c1
	 *            the calendar date 1
	 * @param st
	 *            the calendar date 2
	 * @return
	 */
	public static boolean dateCheck(Calendar c1, Calendar st) {
		if (c1.get(Calendar.DAY_OF_MONTH) == st.get(Calendar.DAY_OF_MONTH)
				&& c1.get(Calendar.MONTH) == st.get(Calendar.MONTH)
				&& c1.get(Calendar.YEAR) == st.get(Calendar.YEAR)
				&& c1.get(Calendar.DAY_OF_YEAR) == st.get(Calendar.DAY_OF_YEAR)
				&& c1.get(Calendar.DAY_OF_WEEK) == st.get(Calendar.DAY_OF_WEEK))
			return true;

		return false;
	}

	/**
	 * This method is used when the used edit his effort of a specific story
	 * which was added previously, and according to the change the others are
	 * changed the effort done is the one enetered in the DB
	 * 
	 * @param sprintId
	 *            Sprint id
	 * @param taskId
	 *            task id
	 * @param dayNum
	 *            dayTask entity we are changing in it
	 * @param effort
	 *            the new effort entered
	 * @param oldEffort
	 *            the old effort
	 * 
	 * @return
	 */
	public static boolean editEffort(long sprintId, long taskId, long dayNum,
			double effort, double oldEffort) {

		Task task = Task.findById(taskId);
		Event sprint = Event.findById(sprintId);
		DayTask taskd = DayTask.findById(dayNum);
		double Effort;
		Day x;
		Day day;
		double dideffort;
		if (dayNum != 1) {
			dideffort = task.initialEffortEstimation;

			for (int i = 0; i < task.dayTasks.size(); i++) {
				if (task.dayTasks.get(i).getEntityId() == taskd.getEntityId())
					break;
				dideffort = dideffort - task.dayTasks.get(i).actualEffort;
			}

			dideffort = dideffort - effort;

		} else {
			day = new Day(sprint.startDate);
			x = Day.find("date", sprint.startDate).first();
			if (x == null)
				day.save();
			else
				day = x;
			Effort = task.initialEffortEstimation;
			dideffort = Effort - effort;

		}

		taskd.actualEffort = dideffort;
		taskd.save();
		return true;
	}

	/**
	 * this method is used to add effort to a specific day which wasn't
	 * previously entered it always enters in the days who's turn is to enter in
	 * 
	 * @param sprintId
	 *            sprint id
	 * @param taskId
	 *            task id
	 * @param dayNum
	 *            task entity to enter in
	 * @param effort
	 *            effort to be entered
	 * @return
	 */
	public static boolean addDayEditEffort(long sprintId, long taskId,
			long dayNum, double effort) {

		Task task = Task.findById(taskId);
		Event sprint = Event.findById(sprintId);

		double dideffort;
		double intial = task.initialEffortEstimation;
		Day day;
		if (task.dayTasks.size() < 1) {
			day = new Day(sprint.startDate);
			List<Day> days = Day.all().fetch();

			boolean there = false;
			for (int j = 0; j < days.size(); j++) {
				if (dateCheck(day.date, days.get(j).date)) {
					day = days.get(j);
					there = true;
				}
			}
			if (!there)
				day.save();
			dideffort = intial - effort;
			DayTask dayTask = new DayTask(dideffort, task, day).save();

		} else {
			int count = task.dayTasks.size();

			DayTask taskd = task.dayTasks.get(count - 1);
			Calendar c1 = new GregorianCalendar();
			c1.set(taskd.day.date.get(Calendar.YEAR), taskd.day.date
					.get(Calendar.MONTH), taskd.day.date
					.get(Calendar.DAY_OF_MONTH));
			c1.add(Calendar.DAY_OF_YEAR, 1);
			List<Day> days = Day.all().fetch();
			day = new Day(c1);
			boolean there = false;
			for (int j = 0; j < days.size(); j++) {
				if (dateCheck(c1, days.get(j).date)) {
					day = days.get(j);
					there = true;
				}
			}
			if (!there)
				day.save();
			if (taskd != null) {
				dideffort = task.initialEffortEstimation;
				for (int i = 0; i < task.dayTasks.size(); i++)
					dideffort = dideffort - task.dayTasks.get(i).actualEffort;
				dideffort = dideffort - effort;
				DayTask dayTask = new DayTask(dideffort, task, day).save();
				task.dayTasks.add(dayTask);
				task.save();
			} else
				flash
						.error("U have to eneter the estimates for the previous days first");
		}
		return true;
	}
}
